package com.geekydoo;

import generated.TaskType;

import java.util.List;
import java.util.logging.Logger;

/**
 * The purpose of this class is to provide other classes the ability to test
 * various user inputs for validity.
 * 
 * @author Patrick Dutch
 */
public class InputValidation {

	private static Logger logger = Logger.getLogger("geekydoo");

	// Regular expressions used during input checking
	private static final String REGEX_TIME = "^(20|21|22|23|[01][0-9]|[0-9])[:]([0-5][0-9]|[0-9])$";
	private static final String REGEX_DATE_LONG =
			"^(0?[1-9]|[12][0-9]|3[01])[-/ .](0?[1-9]|1[012])[-/ .](20)[0-9][0-9]$";
	private static final String REGEX_DATE_SHORT = "^(0?[1-9]|[12][0-9]|3[01])[-/ .](0?[1-9]|1[012])$";
	private static final String REGEX_EMPTY_OR_WHITESPACE = "\\s*";
	private static final String REGEX_RESPONSE_YES = "((?i)yes)|((?i)y)";
	private static final String REGEX_RESPONSE_NO = "((?i)no)|((?i)n)";
	private static final String REGEX_CRITERIA_DATE = "((?i)date|(?i)day)";
	private static final String REGEX_CRITERIA_TIME = "((?i)time)";
	private static final String REGEX_CRITERIA_CATEGORY = "((?i)category|(?i)categories)";

	/**
	 * This method determines whether a time string is valid according to the
	 * program. A valid time string is one of the format HH:MM, where HH is
	 * between 00 and 23 and MM is between 00 and 59.
	 * 
	 * @param timeString The time string to check for validity
	 * @return true if the time is valid, false otherwise
	 */
	public static boolean isValidTimeString(String timeString) {
		if (timeString.matches(REGEX_TIME)) {
			return true;
		}
		logger.info(timeString + " doesn't match the regular expression for times");
		return false;
	}

	/**
	 * This method determines whether a date string is valid according to the
	 * program. A valid date string is one of the format DD-MM-YYYY or DD-MM,
	 * where DD is between 01 and 31, MM is between 01 and 12, and year is
	 * between 2000 and 2099. Note that periods, spaces, and slashes can be
	 * substituted for dashes when forming a valid string.
	 * 
	 * @param dateString The date string to check for validity
	 * @return true if date is valid, false otherwise
	 */
	public static boolean isValidDateString(String dateString) {
		if (dateString.matches(REGEX_DATE_LONG)) {
			return true;
		}
		else if (dateString.matches(REGEX_DATE_SHORT)) {
			return true;
		}
		else {
			logger.info(dateString + " doesn't match the regular expression for dates");
			return false;
		}
	}

	/**
	 * This method determines whether a title is valid according to the program.
	 * A valid title is one which does not consist only of whitespace.
	 * 
	 * @param title The title to check for validity
	 * @return true if title is valid, false otherwise
	 */
	public static boolean isValidTitle(String title) {
		if (title.matches(REGEX_EMPTY_OR_WHITESPACE)) {
			return false;
		}
		return true;
	}

	/**
	 * This method determines whether a response is a valid yes/no response.
	 * 
	 * @param answer The response to check for validity
	 * @return true if the response is valid, false otherwise
	 */
	public static boolean isValidYesNoResponse(String answer) {
		if (answer.matches(REGEX_RESPONSE_YES) || answer.matches(REGEX_RESPONSE_NO)) {
			return true;
		}
		return false;
	}

	/**
	 * This method checks to see if the task id is valid, meaning that there
	 * exists a task in the task list with id equal to the id argument.
	 * 
	 * @param id The id to be tested
	 * @param taskList The task list containing all tasks
	 * @return true if the id is valid, false otherwise
	 */
	public static boolean isValidId(String id, List<TaskType> taskList) {
		try {
			Integer.parseInt(id);
		}
		catch (NumberFormatException e) {
			return false;
		}
		for (int i = 0; i < taskList.size(); i++) {
			if (taskList.get(i).getId().equals(id)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * This method determines whether the criteria argument represents a valid
	 * way to display tasks.
	 * 
	 * @param criteria The criterion to check for validity
	 * @return true if the criterion is valid, false otherwise
	 */
	public static boolean isValidCriteria(String criteria) {
		if (criteria.matches(REGEX_CRITERIA_DATE) || criteria.matches(REGEX_CRITERIA_TIME)
				|| criteria.matches(REGEX_CRITERIA_CATEGORY) || criteria.matches(REGEX_EMPTY_OR_WHITESPACE)) {
			return true;
		}
		return false;
	}

	/**
	 * This method determines whether or not a document link corresponding to
	 * the itemNo argument exists.
	 * 
	 * @param itemNo The link number to check for validity
	 * @param index The total number of document links a task has
	 * @return true if the link number is valid, false otherwise
	 */
	public static boolean isValidLinkNumber(String itemNo, int index) {
		int number = 0;
		try {
			number = Integer.parseInt(itemNo);
		}
		catch (NumberFormatException e) {
			return false;
		}
		if (number < 1 || number > index) {
			return false;
		}
		return true;
	}

}
